namespace Xmef.Library
{
    using System;
    using System.Threading;

    public abstract class SequentialWorkItemContainer<T> : WorkItemContainer<T>, IDisposable
    {
        private AutoResetEvent _handle;
        private static object _sync;

        static SequentialWorkItemContainer()
        {
            _sync = new object();
        }
        protected SequentialWorkItemContainer(T item) : base(item)
        {
            this._handle = new AutoResetEvent(false);
        }

        protected override void Stop()
        {
            SequentialWorkItemContainer<T>.Signal((SequentialWorkItemContainer<T>) this);
        }

        protected override void Start()
        {
            SequentialWorkItemContainer<T>.Wait((SequentialWorkItemContainer<T>) this);
        }

        public static void QueryAsync(SequentialWorkItemContainer<T> item)
        {
            lock (WorkItemContainer<T>.SyncRoot)
            {
                if (item != null)
                {
                    item.Link = WorkItemContainer<T>.Current;
                    WorkItemContainer<T>.Current = item;
                    WorkItemContainer<T>.QueryAsync(item);
                }
            }
        }

        public static void QuerySync(SequentialWorkItemContainer<T> item)
        {
            lock (WorkItemContainer<T>.SyncRoot)
            {
                if (item != null)
                {
                    item.Link = WorkItemContainer<T>.Current;
                    WorkItemContainer<T>.Current = item;
                    WorkItemContainer<T>.QuerySync(item);
                }
            }
        }

        private static void Signal(SequentialWorkItemContainer<T> item)
        {
            item._handle.Set();
        }

        private static void Wait(SequentialWorkItemContainer<T> item)
        {
            SequentialWorkItemContainer<T> previous = (SequentialWorkItemContainer<T>)item.Link;
            if (previous != null)
            {
                previous._handle.WaitOne();
            }
        }

        #region IDisposable Members

        public void Dispose()
        {
            ((IDisposable)_handle).Dispose();
        }

        #endregion
    }
}

